package com.zxl.aop;

import com.alibaba.fastjson.JSONObject;
import com.zxl.annotations.RedisCacheEvict;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Objects;


@Component
@Aspect
@Slf4j
public class RedisCacheEvictAspect {
    @Resource
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.zxl.annotations.RedisCacheEvict)")
    public void cachePointCut() {
    }

    /**
     * @param joinPoint
     * @return
     */
    @Around("cachePointCut()")
    public Object doCache(ProceedingJoinPoint joinPoint) {
        Object result = null;

        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = joinPoint.getTarget().getClass()
                    .getMethod(signature.getName(), signature.getMethod().getParameterTypes());
            RedisCacheEvict redisCacheEvict = method.getAnnotation(RedisCacheEvict.class);

            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(redisCacheEvict.matchValue());
            EvaluationContext context = new StandardEvaluationContext();

            Object[] args = joinPoint.getArgs();
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);
            for (int i = 0; i < Objects.requireNonNull(parameterNames).length; i++) {
                context.setVariable(parameterNames[i], args[i].toString());
            }
            String key = redisCacheEvict.keyPrefix() + "::" + Objects.requireNonNull(expression.getValue(context));
            result = redisTemplate.opsForValue().get(key);
            if (result != null) {
                redisTemplate.delete(key);
            }
            result = args[0];
            joinPoint.proceed();
            redisTemplate.opsForValue().set(key, JSONObject.toJSON(result), redisCacheEvict.timeout(), redisCacheEvict.timeUnit());

        } catch (Throwable throwable) {
            log.error("更新抓拍过滤时间失败：" + throwable.getMessage());
        }
        return result;
    }
}
